# -*- coding:utf-8 -*

'''
    @Description: This Programe was finished to realize the function of Laser ranging
    @filename:Laser.py
    @Author:Frame
    @Date:2018.10.20
'''

import serial
from Myserial import Myserial
from PyQt4 import QtCore
import math
import time


class laser(QtCore.QThread):
    '''
           This class is defined as a laser modle which can get direct range using embed code
        like 0x44/0x4d/0x46.
            The laser model's parameters are as follows:
                1) Type:    H150
                2) Measuring Accuracy:  +/-1mm
                3) Measuring Time:  0.3-2s
                4) Measuring Range: 0.02-50m
                5) Working Voltage: 3v(300 mA)
                6) Laser Type: 635nm,<1mw
            The commd of this modle
            O--(0x4F):  open the Laser light
            C--(0x43):  turn off the Laser light

            D--(0x44):  start the ranging (The speed model is medium)
            M--(0x4d):  start the ranging (The speed model is slow)
            F--(0x46):  start the ranging (The speed model is fast)
    '''

    RangeSignal = QtCore.pyqtSignal(float)

    def __init__(self, serial_baud=19200, parent=None):
        super(laser,self).__init__(parent)

        self.serial_baud = serial_baud
        # get the fixed port of laser
        self.serial_port = '/dev/Laser'
        # get the instrance of the class named Myserial
        self.laser_device = Myserial(self.serial_baud, self.serial_port)
        # model self test
        self.laser_status =  self.laser_self_test()

    def laser_self_test(self):
        '''
            This function can get the status of laser. In orther word,when you get the 'True'
            from this fuction means the laser is functioning normally.
        '''
        self.laser_commd_openLigth = '\x4F'
        self.laser_commd_closeLigth = '\x43'

        if "OK" in ("".join(self.get_laser_data(self.laser_commd_openLigth))):
            if "OK" in ("".join(self.get_laser_data(self.laser_commd_closeLigth))):
                print("--- The Laser is Ok ---")
                return True
            else:
                print("The Laser can not close light!!!")
                return False
        else:
            print("The Laser can not open light!!!")
            return False

    def run(self):
        self.RangeSignal.emit(self.get_laser_distance()) # 发出信号

    def get_laser_data(self, commd_getRangeData='\x44'):
        '''
            This function can get the info of distance when you used it.
                input:
                    commd_getRangeData: the commd of ranging
                return:
                    buf_str: return the buf including distance info
        '''
        buf_str = []
        # get the commd of ranging
        self.laser_commd_ranging = commd_getRangeData
        # send the commd
        self.laser_device.send_TxData(self.laser_commd_ranging, 'str')
        # get the receive data
        buf_str = (self.laser_device.get_RxData_org())[1]
        # remove the useless character
        buf_str = buf_str[2:]

        return buf_str

    def get_laser_distance(self):
        '''
            This function can get the final distance in cm. In this function,some normal
            errors can be handled
        '''
        if self.laser_status != True:
            return -1
        buf_str = []
        distance = 0
        error_code = 0
        laser_info = ""

        buf_str = self.get_laser_data()
        # data handling
        laser_info = "".join(buf_str[:2])

        while laser_info == "Er":         # the laser occour some error
            # get the error code
            error_code = int("".join(buf_str[2:4]))
            # the error can be handled by ranging again
            if error_code in range(5, 10):
                print("Please check Laser,place the model vertically!", "error_code:" + str(error_code))
                # ranging again
                buf_str = self.get_laser_data()
                # data handling
                laser_info = "".join(buf_str[:2])
            elif (error_code in range(1, 5)) or (error_code in range(10, 18)):
                print("The Laser has some physaical error", "error_code:" + str(error_code))
                # turn off the modle
                # the commd of turn_off is 'X'(0x58)
                self.laser_device.send_TxData('\x58', 'str')

        else:                               # the laser is working well,and the data is reasonable
            distance = float("".join(buf_str[1:6])) * 100
        return distance


# laser1 = laser()
# while True:
#     print(laser1.get_laser_distance())
#     time.sleep(1)
